Henry
kai
Lai
1.一個&&或||操作符產生的值不見得是Boolean類型。這個產生的值將總是兩個操作數表達式其中之一的值
2.如果Type(x)是Boolean, 返回比較ToNumber(x) == y 的結果。如果Type(y)是Boolean, 返回比較x == ToNumber(y) 的結果。
Andy:
Chris: 轉型相等 守護運算子 別用 ==false
日安:
turtle:
Jimmy
mango:
a || b;
// 大略等同於
a ? a : b;
a && b;
// 大略等同於
a ? b : a;
隱含的強制轉型:不明顯的任何型別的轉換動作。
絕大部分是因為==
,覺得它讓程式碼更難理解,但我們的目標應該是減少冗贅、反覆套用,以及非必要的實作,以專注更重要的目的。
以強型別的類似虛擬程式碼:
SomeType x = SomeType( AnotherType( y ) )
但如果可以這樣:
SomeType x = SomeType( y )
這樣做的優點:
而 JavaScript 就是有類似這樣的輔助,在隱含轉型也有優點可用。
var a = "42";
var b = "0";
var c = 42;
var d = 0;
a + b; // "420"
c + d; // 42
一樣都是+
運算子,那什麼導致兩者運算結果不同?他要如何知道是字串的相接還是數值的運算?
再看看這個:
var a = [1,2];
var b = [3,4];
a + b; // "1,23,4"
這兩個數值都不是字串,然而他們進行字串的串接。
如果有任一運算元已經是一個字串,或是一個字串表示值,那麼使用+
就會進行字串的相接。
轉化步驟:
+
接收到 object 或 Array[[DefalutValue]]
演算法
+
的任一運算元是字串,那進行的就會是字串的串接,不然就是數值的加法運算。
var a = 42;
var b = a + "";
b; // "42"
所以只要加上空字串就可以強制轉型把數字轉成字串,其步驟:
但如果使用物件,得到的結果不一定會得到相同值。
反過來,如何將字串隱含強制轉型為字串呢?
var a = "3.14";
var b = a - 0;
b; // 3.14
-
只被定義做數值的減法運算,所以運算使a
被迫強制轉型,a/1
和a*1
也可以達成相同效果,那如果是 object 值呢?
var a = [3];
var b = [1];
a - b; // 2
這兩個陣列值都必須變成數字,他們會先變成字串,在強制轉型成數字,以進行數值運算。
可以把特定類型複雜的布林值轉換:
function onlyOne(a,b,c) {
return !!((a && !b && !c) ||
(!a && b && !c) || (!a && !b && c));
}
var a = true;
var b = false;
onlyOne( a, b, b ); // true
onlyOne( b, a, b ); // true
onlyOne( a, b, a ); // false
或
function onlyOne() {
var sum = 0;
for (var i=0; i < arguments.length; i++) {
// 跳过falsy值。与将它们视为0相同,但是避开NaN
if (arguments[i]) {
sum += arguments[i];
}
}
return sum == 1;
}
var a = true;
var b = false;
onlyOne( b, a ); // true
onlyOne( b, a, b, b, b ); // true
onlyOne( b, b ); // false
onlyOne( b, a, b, b, b, a ); // false
或使用明確的強制轉型:
function onlyOne() {
var sum = 0;
for (var i=0; i < arguments.length; i++) {
sum += Number( !!arguments[i] );
}
return sum === 1;
}
var a = 42;
var b = "abc";
var c;
var d = null;
if (a) {
console.log( "yep" ); // yep
}
while (c) {
console.log( "nope, never runs" );
}
c = d ? a : b;
c; // "abc"
if ((a && d) || c) {
console.log( "yep" ); // yep
}
以上非 boolean 的值都會隱含的強制轉型。
這兩個運算子並不會產生一個邏輯值(boolean),而是他們選擇兩個之中其一的運算元:
var a = 42;
var b = "abc";
var c = null;
a || b; // 42
a && b; // "abc"
c || b; // "abc"
c && b; // null
||
和||
會在第一個運算元進行布林的測試,如果運算元不是布林,就會強制轉型。||
來說:
true
,該運算元的結果就是第一個運算元(a 或 c)false
,該運算元的結果就是第二個運算元(b)&&
來說:
true
,該運算元的結果就是第二個運算元(b)false
,該運算元的結果就是第一個運算元(a 或c)一個||
或&&
的值永遠會是其中一個運算元底層的值,而非測試結果。
或許可以這樣記:
a || b;
// 大略等同於:
a ? a : b;
a && b;
// 大略等同於:
a ? b : a;
有個很常用的方法:
function foo(a,b) {
a = a || "hello";
b = b || "world";
console.log( a + " " + b );
}
foo(); // "hello world"
foo( "yeah", "yeah!" ); // "yeah yeah!"
||
常常做備用的預設值,但要小心:
foo( "That's it!", "" ); // "That's it! world" <-- Oops!
這個狀況,我們預期應該是That's it!
,但因為第二個引數是falsy
,所以預設值被替換上去。
如果是這樣,一是確保引數都要是truthy
,不然可以使用三元運算式。
如果是&&
,因為第一個運算子為truthy
,才會選擇第二個運算子,所以又稱守護運算子,第一個運算式的測試會守護第二個運算式。
function foo() {
console.log( a );
}
var a = 42;
a && foo(); // 42
這個狀況就是a
是 truthy 的時候才會呼叫foo();
以復合運算式來說:
var a = 42;
var b = null;
var c = "foo";
if (a && (b || c)) {
console.log( "yep" );
}
'foo'
'foo'
: 回傳 foo
foo
強制轉型為 true
var s1 = Symbol( "cool" );
String( s1 ); // "Symbol(cool)"
var s2 = Symbol( "not cool" );
s2 + ""; // TypeError